#ifndef _ZR_TIMER_SERVICE_H_
#define _ZR_TIMER_SERVICE_H_

#include <boost/date_time/posix_time/posix_time_types.hpp>
namespace hy {

	/// Time traits suitable for use with the deadline timer.
	template <typename Time>
	struct time_traits;

	/// Time traits specialised for posix_time.
	template <>
	struct time_traits<boost::posix_time::ptime>
	{
		/// The time type.
		typedef boost::posix_time::ptime time_type;

		/// The duration type.
		typedef boost::posix_time::time_duration duration_type;

		/// Get the current time.
		static time_type now()
		{
			return boost::posix_time::microsec_clock::universal_time();
		}

		/// Add a duration to a time.
		static time_type add(const time_type& t, const duration_type& d)
		{
			return t + d;
		}

		/// Subtract one time from another.
		static duration_type subtract(const time_type& t1, const time_type& t2)
		{
			return t1 - t2;
		}

		/// Test whether one time is less than another.
		static bool less_than(const time_type& t1, const time_type& t2)
		{
			return t1 < t2;
		}

		/// Convert to POSIX duration type.
		static boost::posix_time::time_duration to_posix_duration(
			const duration_type& d)
		{
			return d;
		}
	};

	template <typename Time_Traits, typename Timer_Scheduler>
	class timer_service
		: public service_base<timer_service<Time_Traits, Timer_Scheduler> >
	{
	public:
		// The time type.
		typedef typename Time_Traits::time_type time_type;

		// The duration type.
		typedef typename Time_Traits::duration_type duration_type;

		// The implementation type of the timer. This type is dependent on the
		// underlying implementation of the timer service.
		struct implementation_type
	//		: private noncopyable
		{
			time_type expiry;
			bool might_have_pending_waits;
		};

		// Constructor.
		timer_service(reactor& io_service)
			: service_base<timer_service<Time_Traits, Timer_Scheduler> >(io_service),
			scheduler_(*use_service<Timer_Scheduler>(io_service))
		{
			scheduler_.init_task();
			scheduler_.add_timer_queue(timer_queue_);
		}

		// Destructor.
		~timer_service()
		{
			scheduler_.remove_timer_queue(timer_queue_);
		}

		// Destroy all user-defined handler objects owned by the service.
		void shutdown_service()
		{
		}

		// Construct a new timer implementation.
		void construct(implementation_type& impl)
		{
			impl.expiry = time_type();
			impl.might_have_pending_waits = false;
		}

		// Destroy a timer implementation.
		void destroy(implementation_type& impl)
		{
			std::size_t count;
			cancel(impl, count);
		}

		// Cancel any asynchronous wait operations associated with the timer.
		hy_err_t cancel(implementation_type& impl, std::size_t& count)
		{
			if (!impl.might_have_pending_waits)
			{
				count = 0;
				return ZR_SUCCESS;
			}
			count = scheduler_.cancel_timer(timer_queue_, &impl);
			impl.might_have_pending_waits = false;
			return ZR_SUCCESS;
		}

		// Get the expiry time for the timer as an absolute time.
		time_type expires_at(const implementation_type& impl) const
		{
			return impl.expiry;
		}

		// Set the expiry time for the timer as an absolute time.
		hy_err_t expires_at(implementation_type& impl,
			const time_type& expiry_time, std::size_t& count)
		{
			count = cancel(impl, count);
			impl.expiry = expiry_time;
			return ZR_SUCCESS;
		}

		// Get the expiry time for the timer relative to now.
		duration_type get_expires_from_now(const implementation_type& impl) const
		{
			return Time_Traits::subtract(expires_at(impl), Time_Traits::now());
		}

		// Set the expiry time for the timer relative to now.
		hy_err_t set_expires_from_now(implementation_type& impl,
			const duration_type& expiry_time, std::size_t& count)
		{
			return expires_at(impl,
				Time_Traits::add(Time_Traits::now(), expiry_time), count);
		}

		// Perform a blocking wait on the timer.
		void wait(implementation_type& impl, hy_err_t& ec)
		{
			time_type now = Time_Traits::now();
			while (Time_Traits::less_than(now, impl.expiry))
			{
				boost::posix_time::time_duration timeout =
					Time_Traits::to_posix_duration(Time_Traits::subtract(impl.expiry, now));
				::timeval tv;
				tv.tv_sec = timeout.total_seconds();
				tv.tv_usec = timeout.total_microseconds() % 1000000;
				int val;
				ec = socketops::select(0, 0, 0, 0, &tv, val);
				now = Time_Traits::now();
			}
			ec = ZR_SUCCESS;
		}

		template <typename Handler>
		class wait_handler : 
			public handler_base_from_member<Handler>
		{
		public:
			wait_handler(reactor& io_service, Handler handler)
				: handler_base_from_member<Handler>(handler),
				io_service_(io_service),
				work_(io_service)
			{
			}

			void operator()(const hy_err_t& result)
			{
				io_service_.post(bind_handler(this->handler_, result));
			}

		private:
			reactor& io_service_;
			reactor_work work_;
		};

		// Start an asynchronous wait on the timer.
		template <typename Handler>
		void async_wait(implementation_type& impl, Handler handler)
		{
			impl.might_have_pending_waits = true;
			scheduler_.schedule_timer(timer_queue_, impl.expiry,
				wait_handler<Handler>(this->get_io_service(), handler), &impl);
		}

	private:
		// The queue of timers.
		timer_queue<Time_Traits> timer_queue_;

		// The object that schedules and executes timers. Usually a reactor.
		Timer_Scheduler& scheduler_;
	};


	/// Default service implementation for a timer.
	template <typename TimeType,
		typename TimeTraits = time_traits<TimeType> >
	class deadline_timer_service
		: public service_base<deadline_timer_service<TimeType, TimeTraits> >
	{
	public:

		/// The time traits type.
		typedef TimeTraits traits_type;

		/// The time type.
		typedef typename traits_type::time_type time_type;

		/// The duration type.
		typedef typename traits_type::duration_type duration_type;

	private:
		// The type of the platform-specific implementation.
#if (ZR_HAVE_IOCP_H)
		typedef timer_service<
			traits_type, iocp_reactor> service_impl_type;
#elif (ZR_HAVE_EPOLL_H)
		typedef timer_service<
			traits_type, epoll_reactor<false> > service_impl_type;
#else
		typedef timer_service<
			traits_type, select_reactor<false> > service_impl_type;
#endif

	public:
		/// The implementation type of the deadline timer.
		typedef typename service_impl_type::implementation_type implementation_type;


		/// Construct a new timer service for the specified io_service.
		explicit deadline_timer_service(reactor& io_service)
			: service_base<
			deadline_timer_service<TimeType, TimeTraits> >(io_service),
			service_impl_(*use_service<service_impl_type>(io_service))
		{
		}

		/// Destroy all user-defined handler objects owned by the service.
		void shutdown_service()
		{
		}

		/// Construct a new timer implementation.
		void construct(implementation_type& impl)
		{
			service_impl_.construct(impl);
		}

		/// Destroy a timer implementation.
		void destroy(implementation_type& impl)
		{
			service_impl_.destroy(impl);
		}

		/// Cancel any asynchronous wait operations associated with the timer.
		hy_err_t cancel(implementation_type& impl, std::size_t &size)
		{
			return service_impl_.cancel(impl, size);
		}

		/// Get the expiry time for the timer as an absolute time.
		time_type expires_at(const implementation_type& impl) const
		{
			return service_impl_.expires_at(impl);
		}

		/// Set the expiry time for the timer as an absolute time.
		 hy_err_t expires_at(implementation_type& impl,
			const time_type& expiry_time, std::size_t& count)
		{
			return service_impl_.expires_at(impl, expiry_time, count);
		}

		/// Get the expiry time for the timer relative to now.
		duration_type get_expires_from_now(const implementation_type& impl) const
		{
			return service_impl_.get_expires_from_now(impl);
		}

		/// Set the expiry time for the timer relative to now.
		hy_err_t set_expires_from_now(implementation_type& impl,
			const duration_type& expiry_time, std::size_t& count)
		{
			return service_impl_.set_expires_from_now(impl, expiry_time, count);
		}

		// Perform a blocking wait on the timer.
		void wait(implementation_type& impl, hy_err_t& ec)
		{
			service_impl_.wait(impl, ec);
		}

		// Start an asynchronous wait on the timer.
		template <typename WaitHandler>
		void async_wait(implementation_type& impl, WaitHandler handler)
		{
			service_impl_.async_wait(impl, handler);
		}

	private:
		// The service that provides the platform-specific implementation.
		service_impl_type& service_impl_;
	};


	/// Provides waitable timer functionality.
	/**
	* The basic_deadline_timer class template provides the ability to perform a
	* blocking or asynchronous wait for a timer to expire.
	*
	* Most applications will use the asio::deadline_timer typedef.
	*
	* @par Thread Safety
	* @e Distinct @e objects: Safe.@n
	* @e Shared @e objects: Unsafe.
	*
	* @par Examples
	* Performing a blocking wait:
	* @code
	* // Construct a timer without setting an expiry time.
	* asio::deadline_timer timer(io_service);
	*
	* // Set an expiry time relative to now.
	* timer.expires_from_now(boost::posix_time::seconds(5));
	*
	* // Wait for the timer to expire.
	* timer.wait();
	* @endcode
	*
	* @par 
	* Performing an asynchronous wait:
	* @code
	* void handler(const asio::error_code& error)
	* {
	*   if (!error)
	*   {
	*     // Timer expired.
	*   }
	* }
	*
	* ...
	*
	* // Construct a timer with an absolute expiry time.
	* asio::deadline_timer timer(io_service,
	*     boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));
	*
	* // Start an asynchronous wait.
	* timer.async_wait(handler);
	* @endcode
	*
	* @par Changing an active deadline_timer's expiry time
	*
	* Changing the expiry time of a timer while there are pending asynchronous
	* waits causes those wait operations to be cancelled. To ensure that the action
	* associated with the timer is performed only once, use something like this:
	* used:
	*
	* @code
	* void on_some_event()
	* {
	*   if (my_timer.expires_from_now(seconds(5)) > 0)
	*   {
	*     // We managed to cancel the timer. Start new asynchronous wait.
	*     my_timer.async_wait(on_timeout);
	*   }
	*   else
	*   {
	*     // Too late, timer has already expired!
	*   }
	* }
	*
	* void on_timeout(const asio::error_code& e)
	* {
	*   if (e != asio::error::operation_aborted)
	*   {
	*     // Timer was not cancelled, take necessary action.
	*   }
	* }
	* @endcode
	*
	* @li The asio::basic_deadline_timer::expires_from_now() function
	* cancels any pending asynchronous waits, and returns the number of
	* asynchronous waits that were cancelled. If it returns 0 then you were too
	* late and the wait handler has already been executed, or will soon be
	* executed. If it returns 1 then the wait handler was successfully cancelled.
	*
	* @li If a wait handler is cancelled, the asio::error_code passed to
	* it contains the value asio::error::operation_aborted.
	*/
	template <typename Time,
		typename TimeTraits = time_traits<Time>,
		typename TimerService = deadline_timer_service<Time, TimeTraits> >
	class basic_deadline_timer
		: public basic_io_object<TimerService>
	{
	public:
		/// The time traits type.
		typedef TimeTraits traits_type;

		/// The time type.
		typedef typename traits_type::time_type time_type;

		/// The duration type.
		typedef typename traits_type::duration_type duration_type;

		/// Constructor.
		/**
		* This constructor creates a timer without setting an expiry time. The
		* expires_at() or expires_from_now() functions must be called to set an
		* expiry time before the timer can be waited on.
		*
		* @param io_service The io_service object that the timer will use to dispatch
		* handlers for any asynchronous operations performed on the timer.
		*/
		explicit basic_deadline_timer(reactor& io_service)
			: basic_io_object<TimerService>(io_service)
		{
		}

		/// Constructor to set a particular expiry time as an absolute time.
		/**
		* This constructor creates a timer and sets the expiry time.
		*
		* @param io_service The io_service object that the timer will use to dispatch
		* handlers for any asynchronous operations performed on the timer.
		*
		* @param expiry_time The expiry time to be used for the timer, expressed
		* as an absolute time.
		*/
		basic_deadline_timer(reactor& io_service,
			const time_type& expiry_time)
			: basic_io_object<TimerService>(io_service)
		{
			hy_err_t ec;
			this->service_.expires_at(this->implementation, expiry_time, ec);
			//asio::detail::throw_error(ec);
		}

		/// Constructor to set a particular expiry time relative to now.
		/**
		* This constructor creates a timer and sets the expiry time.
		*
		* @param io_service The io_service object that the timer will use to dispatch
		* handlers for any asynchronous operations performed on the timer.
		*
		* @param expiry_time The expiry time to be used for the timer, relative to
		* now.
		*/
		basic_deadline_timer(reactor& io_service,
			const duration_type& expiry_time)
			: basic_io_object<TimerService>(io_service)
		{
			hy_err_t ec;
			this->service_.get_expires_from_now(this->implementation, expiry_time, ec);
			//asio::detail::throw_error(ec);
		}

		/// Cancel any asynchronous operations that are waiting on the timer.
		/**
		* This function forces the completion of any pending asynchronous wait
		* operations against the timer. The handler for each cancelled operation will
		* be invoked with the asio::error::operation_aborted error code.
		*
		* Cancelling the timer does not change the expiry time.
		*
		* @param ec Set to indicate what error occurred, if any.
		*
		* @return The number of asynchronous operations that were cancelled.
		*/
		hy_err_t cancel(std::size_t& count)
		{
			return this->service_.cancel(this->implementation, count);
		}

		/// Get the timer's expiry time as an absolute time.
		/**
		* This function may be used to obtain the timer's current expiry time.
		* Whether the timer has expired or not does not affect this value.
		*/
		time_type expires_at() const
		{
			return this->service_.expires_at(this->implementation);
		}

		/// Set the timer's expiry time as an absolute time.
		/**
		* This function sets the expiry time. Any pending asynchronous wait
		* operations will be cancelled. The handler for each cancelled operation will
		* be invoked with the asio::error::operation_aborted error code.
		*
		* @param expiry_time The expiry time to be used for the timer.
		*
		* @param ec Set to indicate what error occurred, if any.
		*
		* @return The number of asynchronous operations that were cancelled.
		*/
		 hy_err_t expires_at(const time_type& expiry_time, std::size_t& count)
		{
			return this->service_.expires_at(this->implementation, expiry_time, count);
		}

		/// Get the timer's expiry time relative to now.
		/**
		* This function may be used to obtain the timer's current expiry time.
		* Whether the timer has expired or not does not affect this value.
		*/
		duration_type get_expires_from_now() const
		{
			return this->service_.get_expires_from_now(this->implementation);
		}

		/// Set the timer's expiry time relative to now.
		/**
		* This function sets the expiry time. Any pending asynchronous wait
		* operations will be cancelled. The handler for each cancelled operation will
		* be invoked with the asio::error::operation_aborted error code.
		*
		* @param expiry_time The expiry time to be used for the timer.
		*
		* @return The number of asynchronous operations that were cancelled.
		*
		* @throws asio::system_error Thrown on failure.
		*/
		hy_err_t set_expires_from_now(const duration_type& expiry_time, std::size_t& count)
		{
			return this->service_.set_expires_from_now(
				this->implementation, expiry_time, count);
		}

		/// Set the timer's expiry time relative to now.
		/**
		* This function sets the expiry time. Any pending asynchronous wait
		* operations will be cancelled. The handler for each cancelled operation will
		* be invoked with the asio::error::operation_aborted error code.
		*
		* @param expiry_time The expiry time to be used for the timer.
		*
		* @param ec Set to indicate what error occurred, if any.
		*
		* @return The number of asynchronous operations that were cancelled.
		*/
		hy_err_t set_expires_from_now(const duration_type& expiry_time)
		{
			std::size_t count = 0;
			return this->service_.set_expires_from_now(
				this->implementation, expiry_time, count);
		}

		/// Perform a blocking wait on the timer.
		/**
		* This function is used to wait for the timer to expire. This function
		* blocks and does not return until the timer has expired.
		*
		* @throws asio::system_error Thrown on failure.
		*/
		void wait()
		{
			hy_err_t ec;
			this->service_.wait(this->implementation, ec);
			//asio::detail::throw_error(ec);
		}

		/// Perform a blocking wait on the timer.
		/**
		* This function is used to wait for the timer to expire. This function
		* blocks and does not return until the timer has expired.
		*
		* @param ec Set to indicate what error occurred, if any.
		*/
		void wait(hy_err_t& ec)
		{
			this->service_.wait(this->implementation, ec);
		}

		/// Start an asynchronous wait on the timer.
		/**
		* This function may be used to initiate an asynchronous wait against the
		* timer. It always returns immediately.
		*
		* For each call to async_wait(), the supplied handler will be called exactly
		* once. The handler will be called when:
		*
		* @li The timer has expired.
		*
		* @li The timer was cancelled, in which case the handler is passed the error
		* code asio::error::operation_aborted.
		*
		* @param handler The handler to be called when the timer expires. Copies
		* will be made of the handler as required. The function signature of the
		* handler must be:
		* @code void handler(
		*   const asio::error_code& error // Result of operation.
		* ); @endcode
		* Regardless of whether the asynchronous operation completes immediately or
		* not, the handler will not be invoked from within this function. Invocation
		* of the handler will be performed in a manner equivalent to using
		* asio::io_service::post().
		*/
		template <typename WaitHandler>
		void async_wait(WaitHandler handler)
		{
			this->service_.async_wait(this->implementation, handler);
		}
	};


	/// Typedef for the typical usage of timer.
	typedef basic_deadline_timer<boost::posix_time::ptime> zr_deadline_timer;

} // namespace zr

#endif
